/*
 * @Author: Suo-Yuheng syh15399227325@163.com
 * @Date: 2025-09-09 16:14:28
 * @LastEditors: Suo-Yuheng syh15399227325@163.com
 * @LastEditTime: 2025-09-09 23:59:01
 * @FilePath: /0909/TcpServer.hpp
 * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
 */
#pragma once

#include <functional>
#include <signal.h>

#include "log.hpp"
#include "Socket.hpp"

using func_t = std::function<std::string(std::string &package)>;

class TcpServer
{
public:
    TcpServer(uint16_t port, func_t callback)
        :port_(port), callback_(callback)
    {}

    bool InitServer()
    {
        listensock_.Socket();
        listensock_.Bind(port_);
        listensock_.Listen();
        lg(Info, "init TcpServer ...... done");

        return true;
    }

    void Start()
    {
        signal(SIGCHLD, SIG_IGN);
        signal(SIGPIPE, SIG_IGN);
        while(true)
        {
            std::string clientip;   // Accept 的 输出型参数
            uint16_t clientport;    // Accept 的 输出型参数
            int sockfd = listensock_.Accept(&clientip, &clientport);  // 从 listensock 中 不断获取 新连接
            if(sockfd < 0) continue;    // 获取连接失败、重新获取
            
            lg(Info, "accept a new link ... , sockfd: %d, clientip: %s, clientport: %d", sockfd, clientip.c_str(), clientport);
            // 获取连接 成功，提供服务 --- 多进程版本
            if(fork() == 0)
            {
                listensock_.Close();    // 子进程继承了文件描述符表，但子进程不需要 监听状态的 套接字（这是父进程用来获取新连接的），直接关掉
                
                // 提供服务...
                std::string inbuffer_stream;    // 这里要定义在 子进程循环读取的外部，因为 inbuffer_stream 可能会存入 读取不完整 的 报文，
                                                // 如果不完整，就直接返回，继续读取，直到读取到完整的一个报文，作处理，返回结果
                while(true)
                {
                    char buffer[128];
                    ssize_t n = read(sockfd, buffer, sizeof(buffer));
                    if(n > 0)   // 读取成功
                    {
                        buffer[n] = '\0';
                        inbuffer_stream += buffer;   // 读取到了 请求的 字节流；这里要使用 += ，避免之前如果读到不完整报文，下次读取会被覆盖掉

                        lg(Debug, "debug: \n%s", inbuffer_stream.c_str());

                        while(true) // 这里的循环，使得可以一次 解析 多个报文，解析完成之后，又去读新的数据
                        {
                            std::string info = callback_(inbuffer_stream);  // 使用 包装器、给 服务器初始化时 传入回调方法
                            if(info.empty()) break;

                            write(sockfd, info.c_str(), info.size());   // 把服务器的返回结果写回 TCP的 发送缓冲区、发送响应
                        }
                    }
                    else
                    {
                        close(sockfd);
                        break;
                    }
                }

                exit(0);
            }

            close(sockfd);  // 对父进程来说，已经把 子进程退出的 信号 忽略了，无需等待
                            // 并且 获取到的新的 套接字 sockfd 被 交给 子进程 去执行对应的任务了，父进程不再需要
            
        }
    }

    ~TcpServer()
    {}
private:
    uint16_t port_;
    Sock listensock_;
    func_t callback_;
};